"""
性能优化和扩展性设计模块
实现Redis+内存缓存混合策略，为RAG等模块预留接口
"""

import asyncio
import time
import json
from typing import Dict, Any, List, Optional, Callable, Union
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from collections import OrderedDict
import logging
import hashlib

logger = logging.getLogger(__name__)

@dataclass
class CacheItem:
    """缓存项"""
    key: str
    value: Any
    timestamp: datetime
    ttl: Optional[int] = None  # 生存时间（秒）
    access_count: int = 0
    last_accessed: datetime = field(default_factory=datetime.now)
    
    def is_expired(self) -> bool:
        """检查是否过期"""
        if self.ttl is None:
            return False
        return datetime.now() > self.timestamp + timedelta(seconds=self.ttl)
    
    def touch(self):
        """更新访问时间"""
        self.access_count += 1
        self.last_accessed = datetime.now()

class LRUCache:
    """LRU缓存实现"""
    
    def __init__(self, max_size: int = 1000, default_ttl: int = 3600):
        self.max_size = max_size
        self.default_ttl = default_ttl
        self.cache: OrderedDict[str, CacheItem] = OrderedDict()
        self._lock = asyncio.Lock()
    
    async def get(self, key: str) -> Optional[Any]:
        """获取缓存项"""
        async with self._lock:
            if key not in self.cache:
                return None
            
            item = self.cache[key]
            
            # 检查是否过期
            if item.is_expired():
                del self.cache[key]
                return None
            
            # 更新访问信息并移到末尾（最近使用）
            item.touch()
            self.cache.move_to_end(key)
            
            return item.value
    
    async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
        """设置缓存项"""
        async with self._lock:
            # 如果已存在，更新
            if key in self.cache:
                self.cache[key].value = value
                self.cache[key].timestamp = datetime.now()
                self.cache[key].ttl = ttl or self.default_ttl
                self.cache.move_to_end(key)
                return True
            
            # 检查容量
            if len(self.cache) >= self.max_size:
                # 移除最久未使用的项
                oldest_key = next(iter(self.cache))
                del self.cache[oldest_key]
            
            # 添加新项
            item = CacheItem(
                key=key,
                value=value,
                timestamp=datetime.now(),
                ttl=ttl or self.default_ttl
            )
            self.cache[key] = item
            
            return True
    
    async def delete(self, key: str) -> bool:
        """删除缓存项"""
        async with self._lock:
            if key in self.cache:
                del self.cache[key]
                return True
            return False
    
    async def clear(self):
        """清空缓存"""
        async with self._lock:
            self.cache.clear()
    
    async def cleanup_expired(self) -> int:
        """清理过期项"""
        async with self._lock:
            expired_keys = [
                key for key, item in self.cache.items()
                if item.is_expired()
            ]
            
            for key in expired_keys:
                del self.cache[key]
            
            return len(expired_keys)
    
    def get_stats(self) -> Dict[str, Any]:
        """获取缓存统计"""
        return {
            "size": len(self.cache),
            "max_size": self.max_size,
            "hit_rate": self._calculate_hit_rate(),
            "oldest_item": min(self.cache.values(), key=lambda x: x.timestamp).timestamp.isoformat() if self.cache else None,
            "newest_item": max(self.cache.values(), key=lambda x: x.timestamp).timestamp.isoformat() if self.cache else None
        }
    
    def _calculate_hit_rate(self) -> float:
        """计算命中率"""
        if not self.cache:
            return 0.0
        
        total_access = sum(item.access_count for item in self.cache.values())
        return total_access / len(self.cache) if total_access > 0 else 0.0

# HybridCacheManager 已移除 - 过度设计的缓存管理器
# 使用简化的缓存策略替代

class AsyncBatchProcessor:
    """异步批处理器"""
    
    def __init__(
        self, 
        batch_size: int = 10, 
        timeout_seconds: float = 5.0,
        max_retries: int = 3
    ):
        self.batch_size = batch_size
        self.timeout_seconds = timeout_seconds
        self.max_retries = max_retries
        self.pending_tasks = []
        self._lock = asyncio.Lock()
        self._processing = False
    
    async def add_task(self, task_func: Callable, *args, **kwargs) -> Any:
        """添加任务到批处理队列"""
        future = asyncio.Future()
        task_item = {
            "func": task_func,
            "args": args,
            "kwargs": kwargs,
            "future": future,
            "timestamp": time.time()
        }
        
        async with self._lock:
            self.pending_tasks.append(task_item)
            
            # 检查是否需要触发批处理
            if len(self.pending_tasks) >= self.batch_size and not self._processing:
                asyncio.create_task(self._process_batch())
        
        return await future
    
    async def _process_batch(self):
        """处理批次"""
        async with self._lock:
            if self._processing or not self.pending_tasks:
                return
            
            self._processing = True
            current_batch = self.pending_tasks[:self.batch_size]
            self.pending_tasks = self.pending_tasks[self.batch_size:]
        
        try:
            # 并发执行批次中的任务
            tasks = []
            for item in current_batch:
                task = asyncio.create_task(
                    self._execute_with_retry(
                        item["func"], 
                        *item["args"], 
                        **item["kwargs"]
                    )
                )
                tasks.append((task, item["future"]))
            
            # 等待所有任务完成
            for task, future in tasks:
                try:
                    result = await asyncio.wait_for(task, timeout=self.timeout_seconds)
                    if not future.done():
                        future.set_result(result)
                except asyncio.TimeoutError:
                    if not future.done():
                        future.set_exception(asyncio.TimeoutError("Task timeout"))
                except Exception as e:
                    if not future.done():
                        future.set_exception(e)
        
        finally:
            async with self._lock:
                self._processing = False
                
                # 如果还有待处理任务，继续处理
                if self.pending_tasks:
                    asyncio.create_task(self._process_batch())
    
    async def _execute_with_retry(self, func: Callable, *args, **kwargs) -> Any:
        """带重试的执行"""
        last_exception = None
        
        for attempt in range(self.max_retries):
            try:
                if asyncio.iscoroutinefunction(func):
                    return await func(*args, **kwargs)
                else:
                    return func(*args, **kwargs)
            except Exception as e:
                last_exception = e
                if attempt < self.max_retries - 1:
                    await asyncio.sleep(0.1 * (2 ** attempt))  # 指数退避
        
        raise last_exception

class ExtensibilityInterface:
    """扩展性接口"""
    
    def __init__(self):
        self.plugins: Dict[str, Any] = {}
        self.hooks: Dict[str, List[Callable]] = {}
        
    def register_plugin(self, name: str, plugin: Any):
        """注册插件"""
        self.plugins[name] = plugin
        logger.info(f"Plugin registered: {name}")
    
    def get_plugin(self, name: str) -> Optional[Any]:
        """获取插件"""
        return self.plugins.get(name)
    
    def register_hook(self, event: str, callback: Callable):
        """注册钩子"""
        if event not in self.hooks:
            self.hooks[event] = []
        self.hooks[event].append(callback)
        logger.info(f"Hook registered for event: {event}")
    
    async def trigger_hook(self, event: str, *args, **kwargs):
        """触发钩子"""
        if event in self.hooks:
            for callback in self.hooks[event]:
                try:
                    if asyncio.iscoroutinefunction(callback):
                        await callback(*args, **kwargs)
                    else:
                        callback(*args, **kwargs)
                except Exception as e:
                    logger.error(f"Hook callback failed for event {event}: {e}")

# RAG接口预留
class RAGInterface:
    """RAG模块接口（预留）"""
    
    def __init__(self):
        self.vector_store = None
        self.retriever = None
        self.embeddings = None
    
    async def initialize(self, config: Dict[str, Any]):
        """初始化RAG组件"""
        # 预留接口，后续实现
        pass
    
    async def add_documents(self, documents: List[Dict[str, Any]]) -> bool:
        """添加文档到向量库"""
        # 预留接口
        pass
    
    async def retrieve_relevant_docs(
        self, 
        query: str, 
        top_k: int = 5
    ) -> List[Dict[str, Any]]:
        """检索相关文档"""
        # 预留接口
        pass
    
    async def generate_with_context(
        self, 
        query: str, 
        context_docs: List[Dict[str, Any]]
    ) -> str:
        """基于上下文生成回答"""
        # 预留接口
        pass
